import qs from "qs";
import * as auth from "auth-provider";
import { useAuth } from "context/auth-context";
import { useCallback } from "react";

const apiUrl = process.env.REACT_APP_API_URL;
interface Config extends RequestInit {
  token?: string;
  data?: object;
}
export const http = async (
  endpoint: string,
  { data, token, headers, ...customConfig }: Config = {}
) => {
  const config = {
    method: "GET",
    headers: {
      Authorization: token ? `Bearer ${token}` : "",
      "Content-Type": data ? "application/json" : "",
    },
    ...customConfig,
  };
  if (config.method.toUpperCase() === "GET") {
    endpoint += `?${qs.stringify(data)}`;
  } else {
    config.body = JSON.stringify(data || {});
  }
  // axios 和 fetch 的表现不一样，axios可以直接在返回状态不为2xx的时候抛出异常
  return window
    .fetch(`${apiUrl}/${endpoint}`, config)
    .then(async (response) => {
      if (response.status === 401) {
        await auth.logout();
        window.location.reload();
        return Promise.reject({ message: "请重新登录" });
      }
      const data = await response.json();
      if (response.ok) {
        return data;
      } else {
        return Promise.reject(data);
      }
    });
};
// JS中的typeof, 是在runtime时运行的
// return typeof 1 === 'number'

// TS 中的typeof, 是在静态环境运行的
// return (...[endpoint, config]: Parameters<typeof http>) =>
export const useHttp = () => {
  const { user } = useAuth();
  // TODO 讲解 TS 操作符 TS Utility Types
  // Utility type的用法: 用泛型给它传入一个其他类型，然后Utility type对这个类型进行某种操作
  return useCallback(
    (...[endpoint, config]: Parameters<typeof http>) =>
      http(endpoint, { ...config, token: user?.token }),
    [user?.token]
  );
};

// 联合类型
// let myFavoriteNumber : string | number
// myFavoriteNumber = 'seven'
// myFavoriteNumber =7

// 类型别名 interface在这种情况下没法替代type
// type FavoriteNumber = string | number
// let roseFN: FavoriteNumber = '6'

// 类型别名在很多情况下可以和interface互换
// interface Person {
//   name:string
// }
// type Person = {name:string}
// let xiaoming:Person ={name:'xx'}

// interface 也没法实现Utility type
// type Person = {
//   name: string,
//   age: number
// }
// type PersonKeys = keyof Person
// type PersonOnlyName = Pick<Person,'name'>
// type age = Exclude<PersonKeys,'name'>
// const xiaoMing: Partial<Person> = {name:'小明'}
// const shenMiRen: Omit<Person, 'name'|'age'>={aaa:'qqq'}

// Partial 的实现
// type Partial<T> = {
//   [P in keyof T]?:T[P];
// }
